﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using TL_Cloud.API.Helpers;
using TL_Cloud.Core.Entities;
using TL_Cloud.Core.Extensions;
using TL_Cloud.Core.Interfaces;
using TL_Cloud.Core.LinkURL;
using TL_Cloud.Core.Services;
using TL_Cloud.Models.BookShop;
using TL_Cloud.RepositoryInterface.BookShop;
using TL_Cloud.ViewModels.BookShop.BaseClass;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace TL_Cloud.API.Controllers
{
    /// <summary>
    /// 班级信息
    /// </summary>
    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ClassesController : ControllerBase
    {
        private readonly ILogger logger;
        private readonly IUnitOfWork _unitOfWork;
        private readonly IBaseClassRepository _classRepository;
        private readonly ITypeHelperService _typeHelperService;
        private readonly IPropertyMappingContainer _propertyMappingContainer = null;
        private readonly IMapper _mapper;
        private readonly IUrlHelper _urlHelper;

        public ClassesController(IMapper mapper,
            ILogger<GradesController> logger,
            ITypeHelperService typeHelperService,
            IPropertyMappingContainer propertyMappingContainer,
            IBaseClassRepository classRepository,
            IUnitOfWork unitOfWork,
            IUrlHelper urlHelper
            )
        {
            this._mapper = mapper;
            this.logger = logger;
            this._typeHelperService = typeHelperService;
            this._classRepository = classRepository;
            this._urlHelper = urlHelper;
            this._propertyMappingContainer = propertyMappingContainer;
            this._unitOfWork = unitOfWork;
        }
       
        /// <summary>
        /// 获取班级信息
        /// </summary>
        /// <param name="classParameters"></param>
        /// <returns></returns>
        [HttpGet(Name = "GetClasses")]
        public async Task<IActionResult> Get([FromQuery]BaseClassQueryParameters classParameters)
        {

            //判断排序是否存在 ，
            if (!_propertyMappingContainer.ValidateMappingExistsFor<BaseClassResource, Base_ClassInfo>(classParameters.OrderBy))
            {
                return BadRequest("Can't finds fields for sorting.");
            }

            //判断fields参数是否在制定的类型中存在
            if (!_typeHelperService.TypeHasProperties<BaseClassResource>(classParameters.Fields))
            {
                return BadRequest("Fields not exist.");
            }

            var classList = await _classRepository.GetAllEntitiesAsync(classParameters);

            var gradeResources = _mapper.Map<IEnumerable<Base_ClassInfo>, IEnumerable<BaseClassResource>>(classList);

            //生成 下一个连接和上一个连接的url
            var previousPageLink = classList.HasPrevious ?
                new LinkUrlCreater<BaseClassQueryParameters>(_urlHelper).CreateGetUrl("GetClasses", classParameters,
                    PaginationResourceUriType.PreviousPage) : null;

            var nextPageLink = classList.HasNext ?
               new LinkUrlCreater<BaseClassQueryParameters>(_urlHelper).CreateGetUrl("GetClasses", classParameters,
                    PaginationResourceUriType.NextPage) : null;


            //数据返回分页数据
            var meta = new
            {
                classList.TotalItemsCount,
                classList.PageSize,
                classList.PageIndex,
                classList.PageCount,
                previousPageLink,
                nextPageLink
            };

            Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
            //返回结果塑性
            return Ok(gradeResources.ToDynamicIEnumerable(classParameters.Fields));
        }

        /// <summary>
        /// 获取单个班级数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        [HttpGet("{id}", Name = "GetClass")]
        public async Task<IActionResult> Get(string id, string fields = null)
        {
            if (!_typeHelperService.TypeHasProperties<BaseClassResource>(fields))
            {
                return BadRequest("Fields not exist.");
            }
            var grade = await _classRepository.GetEntityByIdAsync(id);

            if (grade == null)
            {
                return NotFound();
            }

            var gradeResource = _mapper.Map<Base_ClassInfo, BaseClassResource>(grade);
            var shapedGradeResource = gradeResource.ToDynamic(fields);
            var links = new LinkUrlCreater<BaseClassQueryParameters>(_urlHelper).CreateLinksForPost("GetClass", "DeleteClass", id, fields);
            var result = (IDictionary<string, object>)shapedGradeResource;
            result.Add("links", links);

            return Ok(result);
        }

        /// <summary>
        /// 增加班级数据
        /// </summary>
        [HttpPost(Name = "CreateClass")]
        public async Task<IActionResult> Post([FromBody] BaseClassAddResource gradeAddResource)
        {
            if (gradeAddResource == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var newClassInfo = _mapper.Map<BaseClassAddResource, Base_ClassInfo>(gradeAddResource);
            var userinfo = this.GetUserInfo();
            newClassInfo.Create(userinfo.Item1, userinfo.Item2);
            _classRepository.Add(newClassInfo);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception("Save Failed!");
            }

            var resultResource = _mapper.Map<Base_ClassInfo, BaseClassResource>(newClassInfo);

            var links = new LinkUrlCreater<BaseClassQueryParameters>(_urlHelper).CreateLinksForPost("GetClass", "DeleteClass", newClassInfo.ClassId);
            var linkedPostResource = resultResource.ToDynamic() as IDictionary<string, object>;
            linkedPostResource.Add("links", links);
            return CreatedAtRoute("GetClass", new { id = linkedPostResource["ClassId"] }, linkedPostResource);
        }

        /// <summary>
        /// 修改班级数据
        /// </summary>
        /// <param name="id"></param>
        [HttpPut("{id}", Name = "UpdateClass")]
        public async Task<IActionResult> UpdatePost(string id, [FromBody] BaseClassUpdateResource classUpdate)
        {
            if (classUpdate == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }
            var classinfo = await _classRepository.GetEntityByIdAsync(id);
            if (classinfo == null)
            {
                return NotFound();
            }
            _mapper.Map(classUpdate, classinfo);
            var userinfo = this.GetUserInfo();
            classinfo.Modify(userinfo.Item1,userinfo.Item2);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Updating class {id} failed when saving.");
            }
            return NoContent();
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}", Name = "DeleteClass")]
        public async Task<IActionResult> DeleteClass(string id)
        {
            var post = await _classRepository.GetEntityByIdAsync(id);
            if (post == null)
            {
                return NotFound();
            }

            _classRepository.Delete(post);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Deleting class {id} failed when saving.");
            }

            return NoContent();
        }
    }
}
